﻿using System;
using System.Collections.Generic;
using System.Text;

using Kenly.ChineseSegment.Core;
using Kenly.ChineseSegment.DictionaryLoader;


namespace Kenly.ChineseSegment
{
    /// <summary>
    /// 正向最大匹配分词。
    /// </summary>
    public class ForwardMatchSegment : WordSegmentBase
    {
        private ISegmentDictionary _segmentDictionary = new ForwardSegmentDictionary();
        private List<string> _processedSegements = new List<string>();

        /// <summary>
        /// 
        /// </summary>
        public override ISegmentDictionary SegmentDictionary
        {
            get
            {
                if (_segmentDictionary == null)
                {
                    _segmentDictionary = new ForwardSegmentDictionary();
                }
                return _segmentDictionary;
            }
        }

        /// <summary>
        /// 对单个句子分词。
        /// </summary>
        /// <param name="text"></param>
        /// <param name="result"></param>
        protected override void SegmentSentence(string sentence, ref StringBuilder result)
        {
            if (string.IsNullOrEmpty(sentence))
            {
                return;
            }

            if (this.SegmentDictionary.Segments.Count <= 0)
            {
                return;
            }

            string currentChar;
            //string nextChar;
            string currentTwoChars;

            int charCursor = 0;
            for (charCursor = 0; charCursor < sentence.Length - 1; charCursor++)
            {
                currentChar = sentence.Substring(charCursor, 1);

                //非汉字
                if (!Utility.IsChinese(currentChar))
                {
                    ProcessNonChinese(sentence, result, currentChar, charCursor);
                    continue;
                }

                //汉字
                currentTwoChars = sentence.Substring(charCursor, 2);

                //以当前两字符开头的词，在词库中不存在
                if (!this.SegmentDictionary.Segments.ContainsKey(currentTwoChars))
                {
                    //当前字符是姓
                    if (this.NameSegmentList.Contains(currentChar))
                    {
                        result.Append(currentChar);
                    }
                    else if (this.NameSegmentList.Contains(currentTwoChars))
                    {
                        result.Append(currentTwoChars);
                    }
                    else
                    {
                        result.Append(currentChar);
                        result.Append(this.Separator);
                    }
                    continue;
                }

                //以当前两字符开头的词，在词库中存在,取出所有匹配的词并抽取最大程度的词。
                ProcessExistingElement(sentence, result, currentChar, currentTwoChars, ref charCursor);
            }

            //处理最后一个字符
            ProcessLastChar(sentence, charCursor, result);
        }



        /// <summary>
        /// 处理非汉字
        /// </summary>
        /// <param name="text"></param>
        /// <param name="result"></param>
        /// <param name="currentChar"></param>
        /// <param name="currentIndex"></param>
        private void ProcessNonChinese(string text, StringBuilder result, string currentChar, int currentIndex)
        {
            string nextChar;
            nextChar = text.Substring(currentIndex + 1, 1);

            if (Utility.IsLetter(currentChar) && Utility.IsChinese(nextChar))
            {
                //当前字符是字母，且下一字符是汉字。
                result.Append(currentChar);
                result.Append(this.Separator);
            }
            else
            {
                //当前字符是数字
                result.Append(currentChar);
            }
        }

        /// <summary>
        /// 以当前两字符开头的词，在词库中存在,取出所有匹配的词并抽取最大程度的词。
        /// </summary>
        /// <param name="text"></param>
        /// <param name="result"></param>
        /// <param name="currentTwoChars"></param>
        /// <param name="currentIndex"></param>
        /// <returns></returns>
        private void ProcessExistingElement(string text, StringBuilder result,
            string currentChar, string currentTwoChars, ref int currentIndex)
        {
            //以当前两格字符开头的词。
            List<string> matchedElements = FindMatchedSegments(text.Substring(currentIndex),
                this.SegmentDictionary.Segments[currentTwoChars]);

            //从以当前两格字符开头的词中抽取最大长度的词。
            string maxLenElement = ExstractMaxLenSegment(matchedElements);

            if (maxLenElement.Length > 0)
            {
                AppendMaxLenElement(result, ref currentIndex, maxLenElement);
                foreach (string matchedElement in matchedElements)
                {
                    result.Append(matchedElement);
                    result.Append(this.Separator);
                }

                if (maxLenElement.Length >= 4)
                {
                    ProcessMaxLenElement(result, ref currentIndex, maxLenElement);
                } 
            }
            else
            {
                result.Append(currentChar);
                result.Append(this.Separator);
            }

            //return currentIndex;
        }

        /// <summary>
        /// 继续对最大长度的分词进行分解。
        /// </summary>
        /// <param name="result"></param>
        /// <param name="currentIndex"></param>
        /// <param name="maxLenElement"></param>
        /// <returns></returns>
        private void ProcessMaxLenElement(StringBuilder result, ref int currentIndex, string maxLenElement)
        {
            //长度小于4的，不再分解,直接追加最大长度的分词。
            if (maxLenElement.Length < 4)
            {
                return;
            }

            for (int i = 1; i < maxLenElement.Length - 1; i++)
            {
                string currentTwoChars = maxLenElement.Substring(i, 2);
                if (!this.SegmentDictionary.Segments.ContainsKey(currentTwoChars))
                {
                    continue;
                }

                List<string> matchedElements = FindMatchedSegments(maxLenElement.Substring(i),
                this.SegmentDictionary.Segments[currentTwoChars]);
                string subMaxLenElement = ExstractMaxLenSegment(matchedElements);

                foreach (string matchedElement in matchedElements)
                {
                    result.Append(matchedElement);
                    result.Append(this.Separator);
                }

                if (subMaxLenElement.Length > 0)
                {
                    result.Append(subMaxLenElement);
                    result.Append(this.Separator);
                    i += subMaxLenElement.Length - 1;
                }
            }

            //return AppendMaxLenElement(result, ref currentIndex, maxLenElement);
        }

        /// <summary>
        /// 往结果中追加最大长度的分词。
        /// </summary>
        /// <param name="result"></param>
        /// <param name="currentIndex"></param>
        /// <param name="maxLenElement"></param>
        /// <returns></returns>
        private void AppendMaxLenElement(StringBuilder result, ref int currentIndex, string maxLenElement)
        {
            result.Append(maxLenElement);
            result.Append(this.Separator);
            currentIndex += maxLenElement.Length - 1;
            //return currentIndex;
        }

        /// <summary>
        /// 处理最后一个字符
        /// </summary>
        /// <param name="text"></param>
        /// <param name="currentIndex"></param>
        /// <param name="result"></param>
        private void ProcessLastChar(string text, int currentIndex, StringBuilder result)
        {
            //如果最后一个字符还没有处理
            if (currentIndex < text.Length)
            {
                result.Append(text.Substring(text.Length - 1));
                result.Append(this.Separator);
            }
        }

        /// <summary>
        /// 在目标文本中收索出，以当前两格字符开头的词。
        /// </summary>
        /// <param name="targetText">目标文本</param>
        /// <param name="segmentList">以当前两格字符开头的词。</param>
        /// <returns></returns>
        private List<string> FindMatchedSegments(string targetText, List<string> segmentList)
        {
            List<string> matchedElements = new List<string>();

            foreach (string element in segmentList)
            {
                if (!targetText.StartsWith(element))
                {
                    continue;
                }

                if (!matchedElements.Contains(element))
                {
                    matchedElements.Add(element);
                }
            }

            return matchedElements;
        }

        /// <summary>
        /// 从匹配的分词中抽取最大长度的词。
        /// </summary>
        /// <param name="targetText"></param>
        /// <param name="segmentList"></param>
        /// <param name="maxLenElement"></param>
        /// <returns></returns>
        private string ExstractMaxLenSegment(List<string> matchedElements)
        {
            int maxLen = 0;
            string maxLenElement = "";

            foreach (string element in matchedElements)
            {
                if (element.Length > maxLen)
                {
                    maxLen = element.Length;
                    maxLenElement = element;
                }
            }

            matchedElements.Remove(maxLenElement);

            return maxLenElement;
        }

    }
}
